1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.builder;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertFalse;
21  import static org.junit.Assert.assertNull;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.util.Arrays;
25  
26  import org.junit.Test;
27  
28  /**
29   * Unit tests {@link org.apache.commons.lang3.builder.EqualsBuilder}.
30   *
31   * @version $Id$
32   */
33  public class EqualsBuilderTest {
34  
35      //-----------------------------------------------------------------------
36  
37      static class TestObject {
38          private int a;
39          public TestObject() {
40          }
41          public TestObject(final int a) {
42              this.a = a;
43          }
44          @Override
45          public boolean equals(final Object o) {
46              if (o == null) { return false; }
47              if (o == this) { return true; }
48              if (o.getClass() != getClass()) {
49                  return false;
50              }
51  
52              final TestObject rhs = (TestObject) o;
53              return a == rhs.a;
54          }
55  
56          @Override
57          public int hashCode() {
58              return a;
59          }
60  
61          public void setA(final int a) {
62              this.a = a;
63          }
64  
65          public int getA() {
66              return a;
67          }
68      }
69  
70      static class TestSubObject extends TestObject {
71          private int b;
72          public TestSubObject() {
73              super(0);
74          }
75          public TestSubObject(final int a, final int b) {
76              super(a);
77              this.b = b;
78          }
79          @Override
80          public boolean equals(final Object o) {
81              if (o == null) { return false; }
82              if (o == this) { return true; }
83              if (o.getClass() != getClass()) {
84                  return false;
85              }
86  
87              final TestSubObject rhs = (TestSubObject) o;
88              return super.equals(o) && b == rhs.b;
89          }
90  
91          @Override
92          public int hashCode() {
93              return b *17 + super.hashCode();
94          }
95  
96          public void setB(final int b) {
97              this.b = b;
98          }
99  
100         public int getB() {
101             return b;
102         }
103     }
104     
105     static class TestEmptySubObject extends TestObject {
106         public TestEmptySubObject(final int a) {
107             super(a);
108         }
109     }
110 
111     static class TestTSubObject extends TestObject {
112         @SuppressWarnings("unused")
113         private transient int t;
114         public TestTSubObject(final int a, final int t) {
115             super(a);
116             this.t = t;
117         }
118     }
119 
120     static class TestTTSubObject extends TestTSubObject {
121         @SuppressWarnings("unused")
122         private transient int tt;
123         public TestTTSubObject(final int a, final int t, final int tt) {
124             super(a, t);
125             this.tt = tt;
126         }
127     }
128 
129     static class TestTTLeafObject extends TestTTSubObject {
130         @SuppressWarnings("unused")
131         private final int leafValue;
132         public TestTTLeafObject(final int a, final int t, final int tt, final int leafValue) {
133             super(a, t, tt);
134             this.leafValue = leafValue;
135         }
136     }
137 
138     static class TestTSubObject2 extends TestObject {
139         private transient int t;
140         public TestTSubObject2(final int a, final int t) {
141             super(a);
142         }
143         public int getT() {
144             return t;
145         }
146         public void setT(final int t) {
147             this.t = t;
148         }
149     }
150 
151     @Test
152     public void testReflectionEquals() {
153         final TestObject o1 = new TestObject(4);
154         final TestObject o2 = new TestObject(5);
155         assertTrue(EqualsBuilder.reflectionEquals(o1, o1));
156         assertTrue(!EqualsBuilder.reflectionEquals(o1, o2));
157         o2.setA(4);
158         assertTrue(EqualsBuilder.reflectionEquals(o1, o2));
159 
160         assertTrue(!EqualsBuilder.reflectionEquals(o1, this));
161 
162         assertTrue(!EqualsBuilder.reflectionEquals(o1, null));
163         assertTrue(!EqualsBuilder.reflectionEquals(null, o2));
164         assertTrue(EqualsBuilder.reflectionEquals((Object) null, (Object) null));
165     }
166     
167     @Test
168     public void testReflectionHierarchyEquals() {
169         testReflectionHierarchyEquals(false);
170         testReflectionHierarchyEquals(true);
171         // Transients
172         assertTrue(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), true));
173         assertTrue(EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), false));
174         assertTrue(!EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 0, 0, 4), new TestTTLeafObject(1, 2, 3, 4), true));
175         assertTrue(!EqualsBuilder.reflectionEquals(new TestTTLeafObject(1, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 0), true));
176         assertTrue(!EqualsBuilder.reflectionEquals(new TestTTLeafObject(0, 2, 3, 4), new TestTTLeafObject(1, 2, 3, 4), true));
177     }
178 
179     private void testReflectionHierarchyEquals(final boolean testTransients) {
180         final TestObject to1 = new TestObject(4);
181         final TestObject to1Bis = new TestObject(4);
182         final TestObject to1Ter = new TestObject(4);
183         final TestObject to2 = new TestObject(5);
184         final TestEmptySubObject teso = new TestEmptySubObject(4);
185         final TestTSubObject ttso = new TestTSubObject(4, 1);
186         final TestTTSubObject tttso = new TestTTSubObject(4, 1, 2);
187         final TestTTLeafObject ttlo = new TestTTLeafObject(4, 1, 2, 3);
188         final TestSubObject tso1 = new TestSubObject(1, 4);
189         final TestSubObject tso1bis = new TestSubObject(1, 4);
190         final TestSubObject tso1ter = new TestSubObject(1, 4);
191         final TestSubObject tso2 = new TestSubObject(2, 5);
192 
193         testReflectionEqualsEquivalenceRelationship(to1, to1Bis, to1Ter, to2, new TestObject(), testTransients);
194         testReflectionEqualsEquivalenceRelationship(tso1, tso1bis, tso1ter, tso2, new TestSubObject(), testTransients);
195 
196         // More sanity checks:
197 
198         // same values
199         assertTrue(EqualsBuilder.reflectionEquals(ttlo, ttlo, testTransients));
200         assertTrue(EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(1, 10), testTransients));
201         // same super values, diff sub values
202         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(1, 11), testTransients));
203         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(1, 11), new TestSubObject(1, 10), testTransients));
204         // diff super values, same sub values
205         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(0, 10), new TestSubObject(1, 10), testTransients));
206         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(1, 10), new TestSubObject(0, 10), testTransients));
207 
208         // mix super and sub types: equals
209         assertTrue(EqualsBuilder.reflectionEquals(to1, teso, testTransients));
210         assertTrue(EqualsBuilder.reflectionEquals(teso, to1, testTransients));
211 
212         assertTrue(EqualsBuilder.reflectionEquals(to1, ttso, false)); // Force testTransients = false for this assert
213         assertTrue(EqualsBuilder.reflectionEquals(ttso, to1, false)); // Force testTransients = false for this assert
214 
215         assertTrue(EqualsBuilder.reflectionEquals(to1, tttso, false)); // Force testTransients = false for this assert
216         assertTrue(EqualsBuilder.reflectionEquals(tttso, to1, false)); // Force testTransients = false for this assert
217 
218         assertTrue(EqualsBuilder.reflectionEquals(ttso, tttso, false)); // Force testTransients = false for this assert
219         assertTrue(EqualsBuilder.reflectionEquals(tttso, ttso, false)); // Force testTransients = false for this assert
220 
221         // mix super and sub types: NOT equals
222         assertTrue(!EqualsBuilder.reflectionEquals(new TestObject(0), new TestEmptySubObject(1), testTransients));
223         assertTrue(!EqualsBuilder.reflectionEquals(new TestEmptySubObject(1), new TestObject(0), testTransients));
224 
225         assertTrue(!EqualsBuilder.reflectionEquals(new TestObject(0), new TestTSubObject(1, 1), testTransients));
226         assertTrue(!EqualsBuilder.reflectionEquals(new TestTSubObject(1, 1), new TestObject(0), testTransients));
227 
228         assertTrue(!EqualsBuilder.reflectionEquals(new TestObject(1), new TestSubObject(0, 10), testTransients));
229         assertTrue(!EqualsBuilder.reflectionEquals(new TestSubObject(0, 10), new TestObject(1), testTransients));
230 
231         assertTrue(!EqualsBuilder.reflectionEquals(to1, ttlo));
232         assertTrue(!EqualsBuilder.reflectionEquals(tso1, this));
233     }
234 
235     /**
236      * Equivalence relationship tests inspired by "Effective Java":
237      * <ul>
238      * <li>reflection</li>
239      * <li>symmetry</li>
240      * <li>transitive</li>
241      * <li>consistency</li>
242      * <li>non-null reference</li>
243      * </ul>
244      * @param to a TestObject
245      * @param toBis a TestObject, equal to to and toTer
246      * @param toTer Left hand side, equal to to and toBis
247      * @param to2 a different TestObject
248      * @param oToChange a TestObject that will be changed
249      * @param testTransients whether to test transient instance variables 
250      */
251     private void testReflectionEqualsEquivalenceRelationship(
252         final TestObject to,
253         final TestObject toBis,
254         final TestObject toTer,
255         final TestObject to2,
256         final TestObject oToChange,
257         final boolean testTransients) {
258 
259         // reflection test
260         assertTrue(EqualsBuilder.reflectionEquals(to, to, testTransients));
261         assertTrue(EqualsBuilder.reflectionEquals(to2, to2, testTransients));
262 
263         // symmetry test
264         assertTrue(EqualsBuilder.reflectionEquals(to, toBis, testTransients) && EqualsBuilder.reflectionEquals(toBis, to, testTransients));
265 
266         // transitive test
267         assertTrue(
268             EqualsBuilder.reflectionEquals(to, toBis, testTransients)
269                 && EqualsBuilder.reflectionEquals(toBis, toTer, testTransients)
270                 && EqualsBuilder.reflectionEquals(to, toTer, testTransients));
271 
272         // consistency test
273         oToChange.setA(to.getA());
274         if (oToChange instanceof TestSubObject) {
275             ((TestSubObject) oToChange).setB(((TestSubObject) to).getB());
276         }
277         assertTrue(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
278         assertTrue(EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
279         oToChange.setA(to.getA() + 1);
280         if (oToChange instanceof TestSubObject) {
281             ((TestSubObject) oToChange).setB(((TestSubObject) to).getB() + 1);
282         }
283         assertTrue(!EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
284         assertTrue(!EqualsBuilder.reflectionEquals(oToChange, to, testTransients));
285 
286         // non-null reference test
287         assertTrue(!EqualsBuilder.reflectionEquals(to, null, testTransients));
288         assertTrue(!EqualsBuilder.reflectionEquals(to2, null, testTransients));
289         assertTrue(!EqualsBuilder.reflectionEquals(null, to, testTransients));
290         assertTrue(!EqualsBuilder.reflectionEquals(null, to2, testTransients));
291         assertTrue(EqualsBuilder.reflectionEquals((Object) null, (Object) null, testTransients));
292     }
293 
294     @Test
295     public void testSuper() {
296         final TestObject o1 = new TestObject(4);
297         final TestObject o2 = new TestObject(5);
298         assertTrue(new EqualsBuilder().appendSuper(true).append(o1, o1).isEquals());
299         assertFalse(new EqualsBuilder().appendSuper(false).append(o1, o1).isEquals());
300         assertFalse(new EqualsBuilder().appendSuper(true).append(o1, o2).isEquals());
301         assertFalse(new EqualsBuilder().appendSuper(false).append(o1, o2).isEquals());
302     }
303 
304     @Test
305     public void testObject() {
306         final TestObject o1 = new TestObject(4);
307         final TestObject o2 = new TestObject(5);
308         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
309         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
310         o2.setA(4);
311         assertTrue(new EqualsBuilder().append(o1, o2).isEquals());
312 
313         assertTrue(!new EqualsBuilder().append(o1, this).isEquals());
314         
315         assertTrue(!new EqualsBuilder().append(o1, null).isEquals());
316         assertTrue(!new EqualsBuilder().append(null, o2).isEquals());
317         assertTrue(new EqualsBuilder().append((Object) null, (Object) null).isEquals());
318     }
319     
320     @Test
321     public void testObjectBuild() {
322         final TestObject o1 = new TestObject(4);
323         final TestObject o2 = new TestObject(5);
324         assertEquals(Boolean.TRUE, new EqualsBuilder().append(o1, o1).build());
325         assertEquals(Boolean.FALSE, new EqualsBuilder().append(o1, o2).build());
326         o2.setA(4);
327         assertEquals(Boolean.TRUE, new EqualsBuilder().append(o1, o2).build());
328 
329         assertEquals(Boolean.FALSE, new EqualsBuilder().append(o1, this).build());
330         
331         assertEquals(Boolean.FALSE, new EqualsBuilder().append(o1, null).build());
332         assertEquals(Boolean.FALSE, new EqualsBuilder().append(null, o2).build());
333         assertEquals(Boolean.TRUE, new EqualsBuilder().append((Object) null, (Object) null).build());
334     }
335 
336     @Test
337     public void testLong() {
338         final long o1 = 1L;
339         final long o2 = 2L;
340         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
341         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
342     }
343 
344     @Test
345     public void testInt() {
346         final int o1 = 1;
347         final int o2 = 2;
348         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
349         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
350     }
351 
352     @Test
353     public void testShort() {
354         final short o1 = 1;
355         final short o2 = 2;
356         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
357         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
358     }
359 
360     @Test
361     public void testChar() {
362         final char o1 = 1;
363         final char o2 = 2;
364         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
365         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
366     }
367 
368     @Test
369     public void testByte() {
370         final byte o1 = 1;
371         final byte o2 = 2;
372         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
373         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
374     }
375 
376     @Test
377     public void testDouble() {
378         final double o1 = 1;
379         final double o2 = 2;
380         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
381         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
382         assertTrue(!new EqualsBuilder().append(o1, Double.NaN).isEquals());
383         assertTrue(new EqualsBuilder().append(Double.NaN, Double.NaN).isEquals());
384         assertTrue(new EqualsBuilder().append(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY).isEquals());
385     }
386 
387     @Test
388     public void testFloat() {
389         final float o1 = 1;
390         final float o2 = 2;
391         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
392         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
393         assertTrue(!new EqualsBuilder().append(o1, Float.NaN).isEquals());
394         assertTrue(new EqualsBuilder().append(Float.NaN, Float.NaN).isEquals());
395         assertTrue(new EqualsBuilder().append(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY).isEquals());
396     }
397 
398     @Test
399     public void testAccessors() {
400         final EqualsBuilder equalsBuilder = new EqualsBuilder();
401         assertTrue(equalsBuilder.isEquals());
402         equalsBuilder.setEquals(true);
403         assertTrue(equalsBuilder.isEquals());
404         equalsBuilder.setEquals(false);
405         assertFalse(equalsBuilder.isEquals());
406     }
407 
408     @Test
409     public void testReset() {
410         final EqualsBuilder equalsBuilder = new EqualsBuilder();
411         assertTrue(equalsBuilder.isEquals());
412         equalsBuilder.setEquals(false);
413         assertFalse(equalsBuilder.isEquals());
414         equalsBuilder.reset();
415         assertTrue(equalsBuilder.isEquals());
416     }
417     
418     @Test
419     public void testBoolean() {
420         final boolean o1 = true;
421         final boolean o2 = false;
422         assertTrue(new EqualsBuilder().append(o1, o1).isEquals());
423         assertTrue(!new EqualsBuilder().append(o1, o2).isEquals());
424     }
425 
426     @Test
427     public void testObjectArray() {
428         TestObject[] obj1 = new TestObject[3];
429         obj1[0] = new TestObject(4);
430         obj1[1] = new TestObject(5);
431         obj1[2] = null;
432         TestObject[] obj2 = new TestObject[3];
433         obj2[0] = new TestObject(4);
434         obj2[1] = new TestObject(5);
435         obj2[2] = null;
436         
437         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
438         assertTrue(new EqualsBuilder().append(obj2, obj2).isEquals());
439         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
440         obj1[1].setA(6);
441         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
442         obj1[1].setA(5);
443         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
444         obj1[2] = obj1[1];
445         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
446         obj1[2] = null;
447         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
448                        
449         obj2 = null;
450         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
451         obj1 = null;
452         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
453     }
454 
455     @Test
456     public void testLongArray() {
457         long[] obj1 = new long[2];
458         obj1[0] = 5L;
459         obj1[1] = 6L;
460         long[] obj2 = new long[2];
461         obj2[0] = 5L;
462         obj2[1] = 6L;
463         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
464         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
465         obj1[1] = 7;
466         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
467 
468         obj2 = null;
469         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
470         obj1 = null;
471         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
472     }
473 
474     @Test
475     public void testIntArray() {
476         int[] obj1 = new int[2];
477         obj1[0] = 5;
478         obj1[1] = 6;
479         int[] obj2 = new int[2];
480         obj2[0] = 5;
481         obj2[1] = 6;
482         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
483         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
484         obj1[1] = 7;
485         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
486 
487         obj2 = null;
488         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
489         obj1 = null;
490         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
491     }
492 
493     @Test
494     public void testShortArray() {
495         short[] obj1 = new short[2];
496         obj1[0] = 5;
497         obj1[1] = 6;
498         short[] obj2 = new short[2];
499         obj2[0] = 5;
500         obj2[1] = 6;
501         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
502         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
503         obj1[1] = 7;
504         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
505 
506         obj2 = null;
507         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
508         obj1 = null;
509         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
510     }
511 
512     @Test
513     public void testCharArray() {
514         char[] obj1 = new char[2];
515         obj1[0] = 5;
516         obj1[1] = 6;
517         char[] obj2 = new char[2];
518         obj2[0] = 5;
519         obj2[1] = 6;
520         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
521         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
522         obj1[1] = 7;
523         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
524 
525         obj2 = null;
526         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
527         obj1 = null;
528         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
529     }
530 
531     @Test
532     public void testByteArray() {
533         byte[] obj1 = new byte[2];
534         obj1[0] = 5;
535         obj1[1] = 6;
536         byte[] obj2 = new byte[2];
537         obj2[0] = 5;
538         obj2[1] = 6;
539         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
540         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
541         obj1[1] = 7;
542         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
543 
544         obj2 = null;
545         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
546         obj1 = null;
547         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
548     }
549 
550     @Test
551     public void testDoubleArray() {
552         double[] obj1 = new double[2];
553         obj1[0] = 5;
554         obj1[1] = 6;
555         double[] obj2 = new double[2];
556         obj2[0] = 5;
557         obj2[1] = 6;
558         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
559         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
560         obj1[1] = 7;
561         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
562 
563         obj2 = null;
564         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
565         obj1 = null;
566         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
567     }
568 
569     @Test
570     public void testFloatArray() {
571         float[] obj1 = new float[2];
572         obj1[0] = 5;
573         obj1[1] = 6;
574         float[] obj2 = new float[2];
575         obj2[0] = 5;
576         obj2[1] = 6;
577         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
578         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
579         obj1[1] = 7;
580         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
581 
582         obj2 = null;
583         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
584         obj1 = null;
585         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
586     }
587 
588     @Test
589     public void testBooleanArray() {
590         boolean[] obj1 = new boolean[2];
591         obj1[0] = true;
592         obj1[1] = false;
593         boolean[] obj2 = new boolean[2];
594         obj2[0] = true;
595         obj2[1] = false;
596         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
597         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
598         obj1[1] = true;
599         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
600 
601         obj2 = null;
602         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
603         obj1 = null;
604         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
605     }
606 
607     @Test
608     public void testMultiLongArray() {
609         final long[][] array1 = new long[2][2];
610         final long[][] array2 = new long[2][2];
611         for (int i = 0; i < array1.length; ++i) {
612             for (int j = 0; j < array1[0].length; j++) {
613                 array1[i][j] = (i + 1) * (j + 1);
614                 array2[i][j] = (i + 1) * (j + 1);
615             }
616         }
617         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
618         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
619         array1[1][1] = 0;
620         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
621     }
622 
623     @Test
624     public void testMultiIntArray() {
625         final int[][] array1 = new int[2][2];
626         final int[][] array2 = new int[2][2];
627         for (int i = 0; i < array1.length; ++i) {
628             for (int j = 0; j < array1[0].length; j++) {
629                 array1[i][j] = (i + 1) * (j + 1);
630                 array2[i][j] = (i + 1) * (j + 1);
631             }
632         }
633         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
634         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
635         array1[1][1] = 0;
636         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
637     }
638 
639     @Test
640     public void testMultiShortArray() {
641         final short[][] array1 = new short[2][2];
642         final short[][] array2 = new short[2][2];
643         for (short i = 0; i < array1.length; ++i) {
644             for (short j = 0; j < array1[0].length; j++) {
645                 array1[i][j] = i;
646                 array2[i][j] = i;
647             }
648         }
649         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
650         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
651         array1[1][1] = 0;
652         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
653     }
654 
655     @Test
656     public void testMultiCharArray() {
657         final char[][] array1 = new char[2][2];
658         final char[][] array2 = new char[2][2];
659         for (char i = 0; i < array1.length; ++i) {
660             for (char j = 0; j < array1[0].length; j++) {
661                 array1[i][j] = i;
662                 array2[i][j] = i;
663             }
664         }
665         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
666         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
667         array1[1][1] = 0;
668         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
669     }
670 
671     @Test
672     public void testMultiByteArray() {
673         final byte[][] array1 = new byte[2][2];
674         final byte[][] array2 = new byte[2][2];
675         for (byte i = 0; i < array1.length; ++i) {
676             for (byte j = 0; j < array1[0].length; j++) {
677                 array1[i][j] = i;
678                 array2[i][j] = i;
679             }
680         }
681         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
682         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
683         array1[1][1] = 0;
684         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
685     }
686 
687     @Test
688     public void testMultiFloatArray() {
689         final float[][] array1 = new float[2][2];
690         final float[][] array2 = new float[2][2];
691         for (int i = 0; i < array1.length; ++i) {
692             for (int j = 0; j < array1[0].length; j++) {
693                 array1[i][j] = (i + 1) * (j + 1);
694                 array2[i][j] = (i + 1) * (j + 1);
695             }
696         }
697         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
698         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
699         array1[1][1] = 0;
700         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
701     }
702 
703     @Test
704     public void testMultiDoubleArray() {
705         final double[][] array1 = new double[2][2];
706         final double[][] array2 = new double[2][2];
707         for (int i = 0; i < array1.length; ++i) {
708             for (int j = 0; j < array1[0].length; j++) {
709                 array1[i][j] = (i + 1) * (j + 1);
710                 array2[i][j] = (i + 1) * (j + 1);
711             }
712         }
713         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
714         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
715         array1[1][1] = 0;
716         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
717     }
718 
719     @Test
720     public void testMultiBooleanArray() {
721         final boolean[][] array1 = new boolean[2][2];
722         final boolean[][] array2 = new boolean[2][2];
723         for (int i = 0; i < array1.length; ++i) {
724             for (int j = 0; j < array1[0].length; j++) {
725                 array1[i][j] = i == 1 || j == 1;
726                 array2[i][j] = i == 1 || j == 1;
727             }
728         }
729         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
730         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
731         array1[1][1] = false;
732         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
733         
734         // compare 1 dim to 2.
735         final boolean[] array3 = new boolean[]{true, true};
736         assertFalse(new EqualsBuilder().append(array1, array3).isEquals());
737         assertFalse(new EqualsBuilder().append(array3, array1).isEquals());
738         assertFalse(new EqualsBuilder().append(array2, array3).isEquals());
739         assertFalse(new EqualsBuilder().append(array3, array2).isEquals());
740     }
741 
742     @Test
743     public void testRaggedArray() {
744         final long array1[][] = new long[2][];
745         final long array2[][] = new long[2][];
746         for (int i = 0; i < array1.length; ++i) {
747             array1[i] = new long[2];
748             array2[i] = new long[2];
749             for (int j = 0; j < array1[i].length; ++j) {
750                 array1[i][j] = (i + 1) * (j + 1);
751                 array2[i][j] = (i + 1) * (j + 1);
752             }
753         }
754         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
755         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
756         array1[1][1] = 0;
757         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
758     }
759 
760     @Test
761     public void testMixedArray() {
762         final Object array1[] = new Object[2];
763         final Object array2[] = new Object[2];
764         for (int i = 0; i < array1.length; ++i) {
765             array1[i] = new long[2];
766             array2[i] = new long[2];
767             for (int j = 0; j < 2; ++j) {
768                 ((long[]) array1[i])[j] = (i + 1) * (j + 1);
769                 ((long[]) array2[i])[j] = (i + 1) * (j + 1);
770             }
771         }
772         assertTrue(new EqualsBuilder().append(array1, array1).isEquals());
773         assertTrue(new EqualsBuilder().append(array1, array2).isEquals());
774         ((long[]) array1[1])[1] = 0;
775         assertTrue(!new EqualsBuilder().append(array1, array2).isEquals());
776     }
777 
778     @Test
779     public void testObjectArrayHiddenByObject() {
780         final TestObject[] array1 = new TestObject[2];
781         array1[0] = new TestObject(4);
782         array1[1] = new TestObject(5);
783         final TestObject[] array2 = new TestObject[2];
784         array2[0] = new TestObject(4);
785         array2[1] = new TestObject(5);
786         final Object obj1 = array1;
787         final Object obj2 = array2;
788         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
789         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
790         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
791         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
792         array1[1].setA(6);
793         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
794     }
795 
796     @Test
797     public void testLongArrayHiddenByObject() {
798         final long[] array1 = new long[2];
799         array1[0] = 5L;
800         array1[1] = 6L;
801         final long[] array2 = new long[2];
802         array2[0] = 5L;
803         array2[1] = 6L;
804         final Object obj1 = array1;
805         final Object obj2 = array2;
806         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
807         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
808         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
809         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
810         array1[1] = 7;
811         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
812     }
813 
814     @Test
815     public void testIntArrayHiddenByObject() {
816         final int[] array1 = new int[2];
817         array1[0] = 5;
818         array1[1] = 6;
819         final int[] array2 = new int[2];
820         array2[0] = 5;
821         array2[1] = 6;
822         final Object obj1 = array1;
823         final Object obj2 = array2;
824         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
825         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
826         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
827         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
828         array1[1] = 7;
829         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
830     }
831 
832     @Test
833     public void testShortArrayHiddenByObject() {
834         final short[] array1 = new short[2];
835         array1[0] = 5;
836         array1[1] = 6;
837         final short[] array2 = new short[2];
838         array2[0] = 5;
839         array2[1] = 6;
840         final Object obj1 = array1;
841         final Object obj2 = array2;
842         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
843         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
844         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
845         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
846         array1[1] = 7;
847         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
848     }
849 
850     @Test
851     public void testCharArrayHiddenByObject() {
852         final char[] array1 = new char[2];
853         array1[0] = 5;
854         array1[1] = 6;
855         final char[] array2 = new char[2];
856         array2[0] = 5;
857         array2[1] = 6;
858         final Object obj1 = array1;
859         final Object obj2 = array2;
860         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
861         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
862         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
863         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
864         array1[1] = 7;
865         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
866     }
867 
868     @Test
869     public void testByteArrayHiddenByObject() {
870         final byte[] array1 = new byte[2];
871         array1[0] = 5;
872         array1[1] = 6;
873         final byte[] array2 = new byte[2];
874         array2[0] = 5;
875         array2[1] = 6;
876         final Object obj1 = array1;
877         final Object obj2 = array2;
878         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
879         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
880         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
881         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
882         array1[1] = 7;
883         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
884     }
885 
886     @Test
887     public void testDoubleArrayHiddenByObject() {
888         final double[] array1 = new double[2];
889         array1[0] = 5;
890         array1[1] = 6;
891         final double[] array2 = new double[2];
892         array2[0] = 5;
893         array2[1] = 6;
894         final Object obj1 = array1;
895         final Object obj2 = array2;
896         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
897         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
898         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
899         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
900         array1[1] = 7;
901         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
902     }
903 
904     @Test
905     public void testFloatArrayHiddenByObject() {
906         final float[] array1 = new float[2];
907         array1[0] = 5;
908         array1[1] = 6;
909         final float[] array2 = new float[2];
910         array2[0] = 5;
911         array2[1] = 6;
912         final Object obj1 = array1;
913         final Object obj2 = array2;
914         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
915         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
916         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
917         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
918         array1[1] = 7;
919         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
920     }
921 
922     @Test
923     public void testBooleanArrayHiddenByObject() {
924         final boolean[] array1 = new boolean[2];
925         array1[0] = true;
926         array1[1] = false;
927         final boolean[] array2 = new boolean[2];
928         array2[0] = true;
929         array2[1] = false;
930         final Object obj1 = array1;
931         final Object obj2 = array2;
932         assertTrue(new EqualsBuilder().append(obj1, obj1).isEquals());
933         assertTrue(new EqualsBuilder().append(obj1, array1).isEquals());
934         assertTrue(new EqualsBuilder().append(obj1, obj2).isEquals());
935         assertTrue(new EqualsBuilder().append(obj1, array2).isEquals());
936         array1[1] = true;
937         assertTrue(!new EqualsBuilder().append(obj1, obj2).isEquals());
938     }
939     
940     public static class TestACanEqualB {
941         private final int a;
942 
943         public TestACanEqualB(final int a) {
944             this.a = a;
945         }
946 
947         @Override
948         public boolean equals(final Object o) {
949             if (o == this) {
950                 return true;
951             }
952             if (o instanceof TestACanEqualB) {
953                 return this.a == ((TestACanEqualB) o).getA();
954             }
955             if (o instanceof TestBCanEqualA) {
956                 return this.a == ((TestBCanEqualA) o).getB();
957             }
958             return false;
959         }
960 
961         @Override
962         public int hashCode() {
963             return a;
964         }
965 
966         public int getA() {
967             return this.a;
968         }
969     }
970 
971     public static class TestBCanEqualA {
972         private final int b;
973 
974         public TestBCanEqualA(final int b) {
975             this.b = b;
976         }
977 
978         @Override
979         public boolean equals(final Object o) {
980             if (o == this) {
981                 return true;
982             }
983             if (o instanceof TestACanEqualB) {
984                 return this.b == ((TestACanEqualB) o).getA();
985             }
986             if (o instanceof TestBCanEqualA) {
987                 return this.b == ((TestBCanEqualA) o).getB();
988             }
989             return false;
990         }
991 
992         @Override
993         public int hashCode() {
994             return b;
995         }
996 
997         public int getB() {
998             return this.b;
999         }
1000     }
1001     
1002     /**
1003      * Tests two instances of classes that can be equal and that are not "related". The two classes are not subclasses
1004      * of each other and do not share a parent aside from Object.
1005      * See http://issues.apache.org/bugzilla/show_bug.cgi?id=33069
1006      */
1007     @Test
1008     public void testUnrelatedClasses() {
1009         final Object[] x = new Object[]{new TestACanEqualB(1)};
1010         final Object[] y = new Object[]{new TestBCanEqualA(1)};
1011 
1012         // sanity checks:
1013         assertTrue(Arrays.equals(x, x));
1014         assertTrue(Arrays.equals(y, y));
1015         assertTrue(Arrays.equals(x, y));
1016         assertTrue(Arrays.equals(y, x));
1017         // real tests:
1018         assertTrue(x[0].equals(x[0]));
1019         assertTrue(y[0].equals(y[0]));
1020         assertTrue(x[0].equals(y[0]));
1021         assertTrue(y[0].equals(x[0]));
1022         assertTrue(new EqualsBuilder().append(x, x).isEquals());
1023         assertTrue(new EqualsBuilder().append(y, y).isEquals());
1024         assertTrue(new EqualsBuilder().append(x, y).isEquals());
1025         assertTrue(new EqualsBuilder().append(y, x).isEquals());
1026     }
1027     
1028     /**
1029      * Test from http://issues.apache.org/bugzilla/show_bug.cgi?id=33067
1030      */
1031     @Test
1032     public void testNpeForNullElement() {
1033         final Object[] x1 = new Object[] { Integer.valueOf(1), null, Integer.valueOf(3) };
1034         final Object[] x2 = new Object[] { Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3) };
1035 
1036         // causes an NPE in 2.0 according to:
1037         // http://issues.apache.org/bugzilla/show_bug.cgi?id=33067
1038         new EqualsBuilder().append(x1, x2);
1039     }
1040 
1041     @Test
1042     public void testReflectionEqualsExcludeFields() throws Exception {
1043         final TestObjectWithMultipleFields x1 = new TestObjectWithMultipleFields(1, 2, 3);
1044         final TestObjectWithMultipleFields x2 = new TestObjectWithMultipleFields(1, 3, 4);
1045 
1046         // not equal when including all fields
1047         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2));
1048 
1049         // doesn't barf on null, empty array, or non-existent field, but still tests as not equal
1050         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, (String[]) null));
1051         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {}));
1052         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {"xxx"}));
1053 
1054         // not equal if only one of the differing fields excluded
1055         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {"two"}));
1056         assertTrue(!EqualsBuilder.reflectionEquals(x1, x2, new String[] {"three"}));
1057 
1058         // equal if both differing fields excluded
1059         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, new String[] {"two", "three"}));
1060 
1061         // still equal as long as both differing fields are among excluded
1062         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, new String[] {"one", "two", "three"}));
1063         assertTrue(EqualsBuilder.reflectionEquals(x1, x2, new String[] {"one", "two", "three", "xxx"}));
1064     }
1065 
1066     static class TestObjectWithMultipleFields {
1067         @SuppressWarnings("unused")
1068         private final TestObject one;
1069         @SuppressWarnings("unused")
1070         private final TestObject two;
1071         @SuppressWarnings("unused")
1072         private final TestObject three;
1073 
1074         public TestObjectWithMultipleFields(final int one, final int two, final int three) {
1075             this.one = new TestObject(one);
1076             this.two = new TestObject(two);
1077             this.three = new TestObject(three);
1078         }
1079     }
1080     
1081     /**
1082      * Test cyclical object references which cause a StackOverflowException if
1083      * not handled properly. s. LANG-606
1084      */
1085     @Test
1086     public void testCyclicalObjectReferences() {
1087         final TestObjectReference refX1 = new TestObjectReference(1);
1088         final TestObjectReference x1 = new TestObjectReference(1);
1089         x1.setObjectReference(refX1);
1090         refX1.setObjectReference(x1);
1091 
1092         final TestObjectReference refX2 = new TestObjectReference(1);
1093         final TestObjectReference x2 = new TestObjectReference(1);
1094         x2.setObjectReference(refX2);
1095         refX2.setObjectReference(x2);
1096 
1097         final TestObjectReference refX3 = new TestObjectReference(2);
1098         final TestObjectReference x3 = new TestObjectReference(2);
1099         x3.setObjectReference(refX3);
1100         refX3.setObjectReference(x3);
1101 
1102         assertTrue(x1.equals(x2));
1103         assertNull(EqualsBuilder.getRegistry());
1104         assertFalse(x1.equals(x3));
1105         assertNull(EqualsBuilder.getRegistry());
1106         assertFalse(x2.equals(x3));
1107         assertNull(EqualsBuilder.getRegistry());
1108     }
1109 
1110     static class TestObjectReference {
1111         @SuppressWarnings("unused")
1112         private TestObjectReference reference;
1113         @SuppressWarnings("unused")
1114         private final TestObject one;
1115 
1116         public TestObjectReference(final int one) {
1117             this.one = new TestObject(one);
1118         }
1119 
1120         public void setObjectReference(final TestObjectReference reference) {
1121             this.reference = reference;
1122         }
1123 
1124         @Override
1125         public boolean equals(final Object obj) {
1126             return EqualsBuilder.reflectionEquals(this, obj);
1127         }
1128     }
1129     
1130     @Test
1131     public void testReflectionArrays() throws Exception {
1132 
1133         final TestObject one = new TestObject(1);
1134         final TestObject two = new TestObject(2);
1135 
1136         final Object[] o1 = new Object[] { one };
1137         final Object[] o2 = new Object[] { two };
1138         final Object[] o3 = new Object[] { one };
1139 
1140         assertTrue(!EqualsBuilder.reflectionEquals(o1, o2));
1141         assertTrue(EqualsBuilder.reflectionEquals(o1, o1));
1142         assertTrue(EqualsBuilder.reflectionEquals(o1, o3));
1143         
1144         final double[] d1 = { 0, 1 };
1145         final double[] d2 = { 2, 3 };
1146         final double[] d3 = { 0, 1 };
1147         
1148         assertTrue(!EqualsBuilder.reflectionEquals(d1, d2));
1149         assertTrue(EqualsBuilder.reflectionEquals(d1, d1));
1150         assertTrue(EqualsBuilder.reflectionEquals(d1, d3));
1151     }
1152 
1153 }
1154